package com.sinotrans.auth.config.security;

import java.util.Collection;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.bootstrap.encrypt.KeyProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;

import com.sinotrans.common.entity.AuthClientProperties;
import com.sinotrans.common.entity.AuthProperties;
import com.sinotrans.common.security.auth.JwtRedisAccessTokenConverter;

/**
 * 认证服务器配置
 *
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfig.class);

    @Value("${spring.application.name}")
    private String resourceId;

    @Autowired
    private AuthProperties authProperties;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        InMemoryClientDetailsServiceBuilder builder = clients.inMemory();
        Collection<AuthClientProperties> list = authProperties.getAuthList();
        for (AuthClientProperties authEntity : list) {
            String clientId = authEntity.getClientId();
            String secret = passwordEncoder.encode(authEntity.getSecret());
            String[] grantTypes = authEntity.getGrantTypes();
            String[] authorities = authEntity.getAuthorities();
            String[] scopes = authEntity.getScopes();
            Integer accessTokenValiditySeconds = authEntity.getAccessTokenValiditySeconds();
            Integer refreshTokenValiditySeconds = authEntity.getRefreshTokenValiditySeconds();
            builder.withClient(clientId).secret(secret).authorizedGrantTypes(grantTypes).authorities(authorities)
                    .scopes(scopes).accessTokenValiditySeconds(accessTokenValiditySeconds)
                    .refreshTokenValiditySeconds(refreshTokenValiditySeconds)
                    .additionalInformation(authEntity.getExtension());
        }

    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(resourceId + "/client");
        oauthServer.allowFormAuthenticationForClients().tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.userApprovalHandler(this.userApprovalHandler());
        endpoints.authenticationManager(this.authenticationManager);
        endpoints.accessTokenConverter(this.accessTokenConverter());
        endpoints.tokenStore(this.tokenStore());
    }

    /**
     * 密钥配置
     */
    @Bean
    public KeyProperties keyProperties() {
        return new KeyProperties();
    }

    /**
     * 自定义token
     ***/
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtRedisAccessTokenConverter accessTokenConverter = new JwtRedisAccessTokenConverter(authProperties);
        // 对称加密
        // accessTokenConverter.setSigningKey(signing);

        // 非对称加密
        KeyProperties keyProperties = keyProperties();
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keyProperties.getKeyStore().getLocation(),
                keyProperties.getKeyStore().getSecret().toCharArray());
        accessTokenConverter.setKeyPair(keyStoreKeyFactory.getKeyPair(keyProperties.getKeyStore().getAlias()));
        //
        return accessTokenConverter;
    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public UserApprovalHandler userApprovalHandler() {
        TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
        handler.setTokenStore(tokenStore());
        handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
        handler.setClientDetailsService(clientDetailsService);
        return handler;
    }

    @Bean
    public ApprovalStore approvalStore() throws Exception {
        TokenApprovalStore store = new TokenApprovalStore();
        store.setTokenStore(tokenStore());
        return store;
    }

}
